package com.jiayou


import cn.hutool.core.lang.Console
import cn.hutool.json.JSONException
import cn.hutool.json.JSONUtil
import com.jiayou.autoconfig.WebSocketAutoConfig
import com.jiayou.autoconfig.WebSocketProperties
import com.jiayou.channel.OnRecive
import com.jiayou.channel.OnSend
import com.jiayou.enmu.DataType
import com.jiayou.enmu.StatusCode
import com.jiayou.handler.MessageHandlerImpl
import org.apache.commons.logging.LogFactory
import org.springframework.web.context.WebApplicationContext
import java.io.IOException
import java.util.concurrent.ConcurrentHashMap
import javax.websocket.*
import javax.websocket.server.PathParam


/***
 * 前后端分离模式
 */
open class WebSocketEndpoint() {
    private var log = LogFactory.getLog(WebSocketEndpoint::class.java)

    companion object {
        //SpringIoc副本
        var configurableApplicationContext: WebApplicationContext? = null
            set(value) {
                field = value
                handlerTree()
            }

        @get:Synchronized
        @set:Synchronized
        var onlineCount = 0     //连接数
            private set

        //维护连接对象
        val webSocketMap = ConcurrentHashMap<String, WebSocketEndpoint?>()


        //初始化信息
        private fun handlerTree() {
            //初始化信息
            LogFactory.getLog(WebSocketEndpoint::class.java).info("Global websocket Endpoint have been initialized")
            println("__        __   _                    _        _      ____ _                            _ \n" +
                    "\\ \\      / ___| |__  ___  ___   ___| | _____| |_   / ___| |__   __ _ _ __  _ __   ___| |\n" +
                    " \\ \\ /\\ / / _ | '_ \\/ __|/ _ \\ / __| |/ / _ | __| | |   | '_ \\ / _` | '_ \\| '_ \\ / _ | |\n" +
                    "  \\ V  V |  __| |_) \\__ | (_) | (__|   |  __| |_  | |___| | | | (_| | | | | | | |  __| |\n" +
                    "   \\_/\\_/ \\___|_.__/|___/\\___/ \\___|_|\\_\\___|\\__|  \\____|_| |_|\\__,_|_| |_|_| |_|\\___|_|\n" +
                    " :: Websocket Channel ::        (1.2.RELEASE)  ")
            if (configurableApplicationContext!!.getBean(WebSocketProperties::class.java).log != true)
                LogFactory.getLog(WebSocketEndpoint::class.java).info("There are ${WebSocketAutoConfig.endpointMap.size} handler in total,open log mode to see more")
            else {
                val list = ArrayList<HashMap<String, ArrayList<String>>>()
                WebSocketAutoConfig.endpointMap.forEach { (t, u) ->
                    u.forEach { (_t, _u) ->
                        val l = ArrayList<String>()
                        _u.forEach {
                            it.forEach { (__t, __u) ->
                                l.add("\t\t\t-- ${t}-${__t}  -> $__u")
                            }
                        }
                        list.add(hashMapOf("  " + _t.name to l))
                    }
                }
                LogFactory.getLog(WebSocketEndpoint::class.java).info("There are ${WebSocketAutoConfig.endpointMap.size} handler in total,below is a list of handler")
                println("*****************   Handler  List  **************************")
                println("***                                                       ***")
                list.forEach {
                    it.forEach { (t, u) ->
                        println("***$t:\t\t\t\t\t\t")
                        u.forEach { channel ->
                            println("***$channel\t\t\t\t\t\t")
                        }
                    }
                }
                println("***                                                       ***")
                println("*************************************************************")
            }


        }


    }

    //获取在线人数
    @Synchronized
    protected fun getConnectionCount() = onlineCount


    //获取维护连接对象
    @Synchronized
    protected fun getConnectionMap() = webSocketMap


    //socket的session对象
    private var session: Session? = null


    //该socket的ID
    private var id = ""


    @OnOpen
    open fun onOpen(session: Session?, @PathParam("id") id: String) {
        this.session = session
        this.id = id
        if (webSocketMap.containsKey(id)) {
            webSocketMap.remove(id)
            webSocketMap[id] = this
        } else {
            webSocketMap[id] = this
        }
        if (configurableApplicationContext!!.getBean(WebSocketProperties::class.java).log == true) {
            Console.log("用户连接:$id,当前在线人数为:${++onlineCount}")
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    open fun onClose() {
        if (webSocketMap.containsKey(id)) {
            webSocketMap.remove(id)
            onlineCount--
        }
        if (configurableApplicationContext!!.getBean(WebSocketProperties::class.java).log == true) {
            Console.log("用户  $id 退出!")
        }
    }


    @OnMessage
    open fun onMessage(message: String, session: Session?) {
        try {
            val rec = OnRecive(JSONUtil.parseObj(message)["id"].toString(),
                    JSONUtil.parseObj(message)["from"].toString(),
                    JSONUtil.parseObj(message)["intent"].toString(),
                    DataType.Json,
                    JSONUtil.parseObj(message)["data"].toString())

            val doWork = (configurableApplicationContext
                    ?.getBean(Class.forName("com.jiayou.handler.MessageHandlerImpl"))
                    as MessageHandlerImpl<*>)
                    .doWork(rec)
            if (configurableApplicationContext!!.getBean(WebSocketProperties::class.java).log == true) {
                println("收到客户端 ${rec.from}的消息：" + rec)
            }
            sendMessage(doWork)
        } catch (e: Exception) {
            Console.error(e.message)
            try {
                sendMessage(OnSend(JSONUtil.parseObj(message)["id"].toString(), JSONUtil.parseObj(message)["from"].toString(), StatusCode.Error, null))
            } catch (e: JSONException) {
                Console.error("错误的数据格式：" + e.message)
            }
        }
    }

    /**
     *
     * @param session
     * @param error
     */
    @OnError
    open fun onError(session: Session?, error: Throwable) {
        Console.log("意外的错误:" + id + ",原因:" + error.message)
        error.printStackTrace()
    }

    /**
     * 实现服务器主动推送
     */
    @Throws(IOException::class)
    open fun sendMessage(message: OnSend) {
        try {
            session?.asyncRemote?.sendText(JSONUtil.toJsonPrettyStr(message))
        } catch (e: Exception) {
            Console.error(e.message)
        }
    }

}